package com.dp.order.util;

import com.dp.order.entity.WorkOrder;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author linzizun
 * @version 1.0
 * @since 2021/11/05 10:42
 */
public class ExportUtil {

    public static int lineUp(List<WorkOrder> workOrderList, List<WorkOrder> answerList,
                             int extent, int accuracy, int increment, int times) {
        int len = 0;
        Collections.shuffle(workOrderList);
        if (!workOrderList.isEmpty() && extent >= workOrderList.get(getMaxIndex(workOrderList)).getClothesRodLength()) {
            len = add(len, workOrderList, answerList, getMaxIndex(workOrderList));
        }
        for (int i = workOrderList.size() - 1; i >= 0; i--) {
            if (len + workOrderList.get(i).getClothesRodLength() + 4 <= extent - accuracy) {
                len = add(len, workOrderList, answerList, i);
                continue;
            }
            workOrderList.sort(Comparator.comparingInt(WorkOrder::getClothesRodLength));
            for (int j = workOrderList.size() - 1; j >= 0; j--) {
                if (len + workOrderList.get(j).getClothesRodLength() + 4 <= extent) {
                    len = add(len, workOrderList, answerList, j);
                    break;
                }
            }
            break;
        }
        if (extent - len <= accuracy || workOrderList.isEmpty() && extent - len > 500) {
            return len;
        }
        if (times <= 1) {
            if (extent < 1200) {
                workOrderList.addAll(answerList);
                answerList.clear();
                return 0;
            }
//            extent -= 500;
            increment += 10;
            times = 10;
        }
        workOrderList.addAll(answerList);
        answerList.clear();
        return lineUp(workOrderList, answerList, extent, accuracy + increment, increment, --times);
    }

    public static int sub(int len, List<WorkOrder> workOrderList, List<WorkOrder> answerList, int index) {
        len -= answerList.get(index).getClothesRodLength() + 4;
        workOrderList.add(answerList.get(index));
        answerList.remove(index);
        return len;
    }

    private static int add(int len, List<WorkOrder> workOrderList, List<WorkOrder> answerList, int index) {
        len += workOrderList.get(index).getClothesRodLength() + 4;
        answerList.add(workOrderList.get(index));
        workOrderList.remove(index);
        return len;
    }

    public static int getMinIndex(List<WorkOrder> workOrderList) {
        int minIndex = 0;
        for (int i = 0; i < workOrderList.size(); i++) {
            if (workOrderList.get(i).getClothesRodLength() < workOrderList.get(minIndex).getClothesRodLength()) {
                minIndex = i;
            }
        }
        return minIndex;
    }

    private static int getMaxIndex(List<WorkOrder> workOrderList) {
        int maxIndex = 0;
        for (int i = 0; i < workOrderList.size(); i++) {
            if (workOrderList.get(i).getClothesRodLength() > workOrderList.get(maxIndex).getClothesRodLength()) {
                maxIndex = i;
            }
        }
        return maxIndex;
    }

    public static List<WorkOrder> getPoleOrder(List<WorkOrder> workOrderList, int extent) {
        int bagNum = workOrderList.stream().mapToInt(x -> x.getClothesRodLength() + 4).sum() / extent + 1;
        int len = 0;
        List<WorkOrder> answerList = new ArrayList<>();
        answerList.add(workOrderList.get(workOrderList.size() - 1));
        len += workOrderList.get(workOrderList.size() - 1).getClothesRodLength();
        workOrderList.remove(workOrderList.size() - 1);
        for (int i = workOrderList.size() - bagNum; i >= 0; i--) {
            if (len + workOrderList.get(i).getClothesRodLength() > extent) {
                continue;
            }
            answerList.add(workOrderList.get(i));
            len += workOrderList.get(i).getClothesRodLength();
            workOrderList.remove(i);
        }
        while (extent - len > 50 && extent - len < 500) {
            len -= answerList.get(0).getClothesRodLength();
            workOrderList.add(workOrderList.size() - bagNum + 1, answerList.get(0));
            answerList.remove(0);
        }
        return answerList;
    }

    public static <T> Workbook export(String[] header, String[] fieldNames, List<T> data) {
        Workbook wb = new HSSFWorkbook();
        int rowSize = 0;
        Sheet sheet = wb.createSheet();
        Row row = sheet.createRow(rowSize);
        for (int i = 0; i < header.length; i++) {
            row.createCell(i).setCellValue(header[i]);
        }
        try {
            for (int x = 0; x < data.size(); x++) {
                rowSize = 1;
                Row rowNew = sheet.createRow(rowSize + x);
                for (int i = 0; i < header.length; i++) {
                    T t = data.get(x);
                    for (int i1 = 0; i1 < fieldNames.length; i1++) {
                        //获取属性的get方法名
                        String methodName = "get" + fieldNames[i].substring(0, 1).toUpperCase() + fieldNames[i].substring(1);
                        Method method = t.getClass().getMethod(methodName);
                        //获取属性值
                        Object invoke = method.invoke(t);
                        rowNew.createCell(i).setCellValue(invoke.toString());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return wb;
    }

    public static String[] fieldName(Class clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();
        String[] fieldNames = new String[declaredFields.length];
        for (int i = 0; i < declaredFields.length; i++) {
            //通过反射获取属性名
            fieldNames[i] = declaredFields[i].getName();
        }
        return fieldNames;
    }

}
